package com.mime.qweibo;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;   
import org.apache.http.client.methods.HttpPost;   
import org.apache.http.client.methods.HttpUriRequest; 
import org.apache.http.HttpResponse;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.entity.mime.Header;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;

import android.net.http.AndroidHttpClient;

import com.mime.qweibo.utils.QHttpUtil;

/**
 * Note: This is not really an async http client. You may try
 * Ning(https://github.com/AsyncHttpClient/async-http-client), Apache Geronimo
 * async-http-client, or anything else if you really need.
 * 
 */
public class QAsyncHttpClient {

	private static final int CONNECTION_TIMEOUT = 20000;

	/**
	 * Using asynchronously GET method.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
	public boolean httpGet(String url, String queryString,
			QAsyncHandler callback, Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		if (queryString != null && !queryString.equals("")) {
			url += "?" + queryString;
		}
		HttpGet httpGet = new HttpGet(url);
		httpGet.getParams().setParameter("http.socket.timeout",
				new Integer(CONNECTION_TIMEOUT));
		mThreadPool.submit(new AsyncThread(httpGet, callback, cookie));
		return true;
	}
	


	/**
	 * Using asynchronously POST method.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
	public boolean httpPost(String url, String queryString,
			QAsyncHandler callback, Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		HttpPost httpPost = new HttpPost(url);
		HttpParams httpParams = new BasicHttpParams();
		httpParams.setParameter("Content-Type", "application/x-www-form-urlencoded");
		HttpConnectionParams.setConnectionTimeout(httpParams, new Integer(CONNECTION_TIMEOUT));
		httpPost.setParams(httpParams);
		if (queryString != null && !queryString.equals("")) {
			List<QParameter> listParams = QHttpUtil.getQueryParameters(queryString);
			MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
			for (QParameter param : listParams) {
				try {
					entity.addPart(param.mName, new StringBody(QHttpUtil.formParamDecode(param.mValue)));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
					return false;
				}				
			}
			httpPost.setEntity(entity);
		}
		mThreadPool.submit(new AsyncThread(httpPost, callback, cookie));
		return true;
	}

	/**
	 * Using asynchronously POST method with multiParts.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
	public boolean httpPostWithFile(String url, String queryString,
			List<QParameter> files, QAsyncHandler callback, Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		url += '?' + queryString;
		HttpPost httpPost = new HttpPost(url);
		List<QParameter> listParams = QHttpUtil.getQueryParameters(queryString);
		MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
		for (QParameter param : listParams) {
			try {
				entity.addPart(param.mName, new StringBody(URLEncoder.encode(QHttpUtil.formParamDecode(param.mValue), "UTF-8")));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				return false;
			}
		}
		for (QParameter param : files) {
			File file = new File(param.mValue);
			entity.addPart(param.mName, new FileBody(file));
		}
		
		httpPost.setEntity(entity);
		
		mThreadPool.submit(new AsyncThread(httpPost, callback, cookie));
		return true;
	}

	private ExecutorService mThreadPool = Executors.newFixedThreadPool(20);

	/**
	 * Thread for asynchronous HTTP request.
	 * 
	 */
	class AsyncThread extends Thread {

		private HttpUriRequest mHttpMedthod;
		private QAsyncHandler mAsyncHandler;
		private Object mCookie;

		public AsyncThread(HttpUriRequest method, QAsyncHandler handler,
				Object cookie) {
			this.mHttpMedthod = method;
			this.mAsyncHandler = handler;
			this.mCookie = cookie;
		}

		@Override
		public void run() {
			String responseData = null;
			DefaultHttpClient httpClient = new DefaultHttpClient();
			int statusCode = -1;
			HttpResponse response;
			try {
				response = httpClient.execute(mHttpMedthod);
				if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
					System.err.println("HttpMethod failed: "
							+ response.getStatusLine());
				}
				responseData = QHttpClient.getResponseBody(response);
			} catch (ParseException  e) {
				e.printStackTrace();
				if (mAsyncHandler != null) {
					mAsyncHandler.onThrowable(e, mCookie);
				}
				return;
			} catch (IOException e) {
				e.printStackTrace();
				if (mAsyncHandler != null) {
					mAsyncHandler.onThrowable(e, mCookie);
				}
				return;
			} finally {
				httpClient = null;
			}
			if (mAsyncHandler != null) {
				mAsyncHandler.onCompleted(statusCode, responseData, mCookie);
			}
		}

	}
}
